package dirty

import (
	"strings"
	"testing"

	"fmt"
)

func TestLoadEmptyArray(t *testing.T) {
	r := strings.NewReader("()")

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if len(arr) != 0 {
		t.Fatalf("expected empty array, got %+v\n", arr)
	}
}

func TestLoadEmptyArrayInArray(t *testing.T) {
	r := strings.NewReader("(())")

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && len(arr[0].(Array)) == 0) {
		t.Fatalf("expected empty array in array, got %+v\n", arr)
	}
}

func TestLoadEmptyArrayWithComment(t *testing.T) {
	r := strings.NewReader(`
   (
     # this is a comment
   )
	`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if len(arr) != 0 {
		t.Fatalf("expected empty array, got %+v\n", arr)
	}
}

func TestLoadArrayWithString(t *testing.T) {
	r := strings.NewReader(`('this is a string')`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(String) == "this is a string") {
		t.Fatalf("expected [‘this is a string’], got %+v\n", arr)
	}
}

func TestEscapeTab(t *testing.T) {
	r := strings.NewReader(`('tab\t')`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(String) == "tab\t") {
		t.Fatalf("expected [‘tab\t’], got %+v\n", arr)
	}
}

func TestEscapeNewline(t *testing.T) {
	r := strings.NewReader(`('nl\n')`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(String) == "nl\n") {
		t.Fatalf("expected [‘nl\n’], got %+v\n", arr)
	}
}

func TestEscapeBackslash(t *testing.T) {
	r := strings.NewReader(`('bs\\')`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(String) == "bs\\") {
		t.Fatalf("expected [‘bs\\’], got %+v\n", arr)
	}
}

func TestEscapeCarret(t *testing.T) {
	r := strings.NewReader(`('\rcarret')`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(String) == "\rcarret") {
		t.Fatalf("expected [‘\rcarret’], got %+v\n", arr)
	}
}

func TestEscapeApos(t *testing.T) {
	r := strings.NewReader(`('\'')`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(String) == "'") {
		t.Fatalf("expected [‘'’], got %+v\n", arr)
	}
}

func TestTrue(t *testing.T) {
	r := strings.NewReader(`(true)`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(Const) == TRUE) {
		t.Fatalf("expected [true], got %+v\n", arr)
	}
}

func TestFalse(t *testing.T) {
	r := strings.NewReader(`(false)`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(Const) == FALSE) {
		t.Fatalf("expected [false], got %+v\n", arr)
	}
}

func TestNull(t *testing.T) {
	r := strings.NewReader(`(null)`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(Const) == NULL) {
		t.Fatalf("expected [null], got %+v\n", arr)
	}
}

func TestU1B(t *testing.T) {
	r := strings.NewReader(`('\u0040')`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(String) == "@") {
		t.Fatalf("expected [‘@’], got %+v\n", arr)
	}
}

func TestU2B(t *testing.T) {
	r := strings.NewReader(`('\u00E5')`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(String) == "å") {
		t.Fatalf("expected [‘å’], got %+v\n", arr)
	}
}

func TestU3B(t *testing.T) {
	r := strings.NewReader(`('\u2042')`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(String) == "⁂") {
		t.Fatalf("expected [‘⁂’], got %+v\n", arr)
	}
}

func TestU4B(t *testing.T) {
	r := strings.NewReader(`('\U000200D1')`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(String) == "𠃑") {
		t.Fatalf("expected [‘𠃑’], got %+v\n", arr)
	}
}

func Test0b(t *testing.T) {
	r := strings.NewReader(`(0b01)`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(Int) == 1) {
		t.Fatalf("expected [1], got %+v\n", arr)
	}
}

func Test0bCommaMiddle(t *testing.T) {
	r := strings.NewReader(`(0b01,00000000)`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(Int) == 0b100000000) {
		t.Fatalf("expected [256], got %+v\n", arr)
	}
}

func Test0bCommaBegin(t *testing.T) {
	r := strings.NewReader(`(0b,00000000)`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(Int) == 0b100000000) {
		t.Fatalf("expected [256], got %+v\n", arr)
	}
}

func Test0bCommas(t *testing.T) {
	r := strings.NewReader(`(0b01,,00000000)`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(Int) == 0b10000000000000000) {
		t.Fatalf("expected [65536], got %+v\n", arr)
	}
}

func Test0o(t *testing.T) {
	r := strings.NewReader(`(0o77)`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(Int) == 0o77) {
		t.Fatalf("expected [63], got %+v\n", arr)
	}
}

func Test0x(t *testing.T) {
	r := strings.NewReader(`(0xff)`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(Int) == 0xff) {
		t.Fatalf("expected [255], got %+v\n", arr)
	}
}

func Test0(t *testing.T) {
	r := strings.NewReader(`(0)`)

	arr, err := Load(r)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
	if !(len(arr) == 1 && arr[0].(Int) == 0) {
		t.Fatalf("expected [0], got %+v\n", arr)
	}
}

// todo test not show
func TestNumbers(t *testing.T) {
	r := strings.NewReader(`(1 10 10. 10.5 ↊· ↊·6 1e2 -1 -10 -10.5 -↊· -↊·6 -1e2 1e-2 -1e-2)`)

	arr, err := Load(r)
	fmt.Println(arr)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
}

func TestShowRawString(t *testing.T) {
	r := strings.NewReader("(`\n" +
		" a\n" +
		" `sql`\n" +
		"`)")

	arr, err := Load(r)
	fmt.Println(arr)
	if err != nil {
		t.Fatalf("got error: %v\n", err)
	}
}

func TestShowLoadStruct(t *testing.T) {
	/*a := ""
	b := 5*/
	r := strings.NewReader(`(
		('a' 'sss')
		('b' 42)
		('c' 3.14)
		('d' null)
		('e' true)
		('f' false)
		('g' 5)
	)`)
	s := &struct {
		A string
		B int
		C float32
		D *int
		E bool
		F bool
		G *int
	}{}
	LoadStruct(r, s)
	fmt.Println(*s.G)

	r = strings.NewReader(`(
		('a' (
			('b' true)
		))
	)`)
	LoadStruct(r, &struct {
		A struct {
			B bool
			C bool
		}
	}{})
	r = strings.NewReader(`(
		('a' 'sss')
		('b' 42)
		('c' 3.14)
	)`)
	LoadStruct(r, &struct {
		z string
	}{})
	/*LoadStruct(nil, &[]int{})
	LoadStruct(nil, &map[string]int{})
	LoadStruct(nil, &a)
	LoadStruct(nil, &b)*/
}

func TestShowLoadMap(t *testing.T) {
	r := strings.NewReader(`(
		('a' 11)
		('b' 42)
		('c' 3)
	)`)
	m := map[string]int{}
	LoadStruct(r, &m)
}

func TestShowLoadMapInt(t *testing.T) {
	r := strings.NewReader(`(
		(1 11)
		(2 42)
		(4 3)
	)`)
	m := map[int]int{}
	LoadStruct(r, &m)
}

func TestShowLoadMapInt8(t *testing.T) {
	r := strings.NewReader(`(
		(1 11)
		(2 42)
		(4 3)
	)`)
	m := map[int8]int{}
	LoadStruct(r, &m)
}

func TestShowLoadMapInt16(t *testing.T) {
	r := strings.NewReader(`(
		(1 11)
		(2 42)
		(4 3)
	)`)
	m := map[int16]int{}
	LoadStruct(r, &m)
}

func TestShowLoadMapInt32(t *testing.T) {
	r := strings.NewReader(`(
		(1 11)
		(2 42)
		(4 3)
	)`)
	m := map[int32]int{}
	LoadStruct(r, &m)
}

func TestShowLoadMapInt64(t *testing.T) {
	r := strings.NewReader(`(
		(1 11)
		(2 42)
		(4 3)
	)`)
	m := map[int64]int{}
	LoadStruct(r, &m)
}

func TestShowLoadMapUInt(t *testing.T) {
	r := strings.NewReader(`(
		(1 11)
		(2 42)
		(4 3)
	)`)
	m := map[uint]int{}
	LoadStruct(r, &m)
}

func TestShowLoadMapUInt8(t *testing.T) {
	r := strings.NewReader(`(
		(1 11)
		(2 42)
		(4 3)
	)`)
	m := map[uint8]int{}
	LoadStruct(r, &m)
}

func TestShowLoadMapUInt16(t *testing.T) {
	r := strings.NewReader(`(
		(1 11)
		(2 42)
		(4 3)
	)`)
	m := map[uint16]int{}
	LoadStruct(r, &m)
}

func TestShowLoadMapUInt32(t *testing.T) {
	r := strings.NewReader(`(
		(1 11)
		(2 42)
		(4 3)
	)`)
	m := map[uint32]int{}
	LoadStruct(r, &m)
}

func TestShowLoadMapUInt64(t *testing.T) {
	r := strings.NewReader(`(
		(1 11)
		(2 42)
		(4 3)
	)`)
	m := map[uint64]int{}
	LoadStruct(r, &m)
}

func TestShowLoadMapBool(t *testing.T) {
	r := strings.NewReader(`(
		(true 11)
		(false 42)
	)`)
	m := map[bool]int{}
	LoadStruct(r, &m)
}

func TestShowLoadArray(t *testing.T) {
	r := strings.NewReader(`(11 22 31)`)
	s := [3]int64{}
	LoadStruct(r, &s)
}

func TestShowLoadSlice(t *testing.T) {
	r := strings.NewReader(`(11 22 31)`)
	s := []int64{}
	LoadStruct(r, &s)
}

func TestShowLoadMapArray(t *testing.T) {
	r := strings.NewReader(`(
		(
			('a' 1)
			('b' 2)
		)
	)`)
	s := []map[string]int{}
	LoadStruct(r, &s)
	fmt.Println(s)
}

//todo escapeError, unterminatedError, invalidCharError, invalidCodepointError, constError, commaError
//todo syntax errors
